package fs.tileMap {
	import adobe.utils.CustomActions;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.printing.PrintJobOptions;
	import flash.text.engine.GroupElement;
	import fs.tileMap.Character;
	import fs.tileMap.data.MapData;
	import fs.tileMap.manager.IHitManager;
	import fs.tileMap.view.tile.AbstractTile;
	import fs.tileMap.view.tile.ITile;
	import fs.tileMap.view.tileFactory.DefaultTileFactory;
	import fs.tileMap.view.tileFactory.ITileFactory;
	
	/**
	 * ...
	 * @author flyingSnow
	 */
	public class TileMap extends Sprite{
		private var _mapData:MapData;
		private var _vecTiles:Vector.<AbstractTile>;
		private var _clCount:int;
		private var _rwCount:int;
		private var _totalCount:int;
		private var _tileFactory:ITileFactory;
		private var _chars:Vector.<Character>;
		private var _mainChar:Character;
		
		private var _tileLayer:Sprite;
		private var _tileWidth:uint;
		private var _tileHeight:uint;
		
		private var _hitManager:IHitManager;
		private var _globalForce:Point;
		
		public function TileMap(mapData:MapData,tileFactory:ITileFactory) {
			this._tileFactory = tileFactory;
			this._mapData = mapData;
			
			_clCount = Math.ceil(_mapData.viewPort.width) + 2;
			_rwCount = Math.ceil(_mapData.viewPort.height) + 2;
			_totalCount = _clCount * _rwCount;
			
			_chars = new Vector.<Character>();
			_globalForce = new Point();
		}
		
		
		//{ region 
		
		//--
		public function prepareTiles():void {
			_vecTiles = new Vector.<AbstractTile>();
			
			_tileLayer = new Sprite();
			addChild(_tileLayer);
			
			for (var cl:int = 0; cl < _clCount; cl++) {
				for (var rw:int = 0; rw < _rwCount; rw++) {
					var tile:AbstractTile = _tileFactory.getTile();
					_tileLayer.addChild(tile);
					tile.x = cl * tile.getTileWidth();
					tile.y = rw * tile.getTileHeight();
					_tileWidth = tile.getTileWidth();
					_tileHeight = tile.getTileHeight();
					//(tile as MyMapTile).text = _vecTiles.length + "";
					_vecTiles.push(tile);
				}
			}
			render();
		}
		//--
		public function loop():void {
			checkHit();
			render();
		}
		
		//private function moveChars():void {
			//for each(var char:Character in _chars) {
				//char.x += char.v.x;
				//char.y += char.v.y;
				//char.v = char.v.add(char.a);
			//}
		//}
		//--
		private function checkHit():void {
			for each(var char:Character in _chars) {
				//
				var oldx:Number = char.x;
				var oldy:Number = char.y;
				
				var oldBound:Rectangle = char.getHitBounds(_tileLayer);
				char.x += char.v.x;
				char.y += char.v.y;
				var newBound:Rectangle = char.getHitBounds(_tileLayer);
				
				//
				var oldGrid:Rectangle = new Rectangle(int((oldBound.x+0.00001) / _tileWidth), 
													int((oldBound.y+0.0001)/_tileHeight));
				oldGrid.right = int((oldBound.right-0.00001) / _tileWidth);
				oldGrid.bottom = int((oldBound.bottom-0.0001) / _tileHeight);
				
				var newGrid:Rectangle = new Rectangle(int(newBound.x / _tileWidth), 
													int(newBound.y/_tileHeight));
				newGrid.right = int(newBound.right / _tileWidth);
				newGrid.bottom = int(newBound.bottom / _tileHeight);
				
				//
				var hitTop:Boolean = newGrid.top<oldGrid.top;
				var hitRight:Boolean = newGrid.right > oldGrid.right;
				var hitBottom:Boolean = newGrid.bottom > oldGrid.bottom;
				var hitLeft:Boolean = newGrid.left < oldGrid.left;

				var hasHitTop:Boolean;
				var hasHitRight:Boolean;
				var hasHitBottom:Boolean;
				var hasHitLeft:Boolean;
				
				var angleHitTest:Boolean;
				
				var rw:int;
				var cl:int;
				
				if (hitLeft && hitTop) {
					//左上
					hasHitLeft = false;
					for (rw = newGrid.top + 1; rw <= newGrid.bottom; rw++ ) {
						hasHitLeft ||= _hitManager.onHit(char,
										                _vecTiles[newGrid.left * _rwCount + rw],
										                2);
					}
					
					hasHitTop = false;
					for (cl = newGrid.left + 1; cl <= newGrid.right; cl++ ) {
						hasHitTop ||= _hitManager.onHit(char,
										                _vecTiles[cl * _rwCount + newGrid.top],
										                4);
					}
					
					if ((!hasHitTop) && (!hasHitLeft)) {
						angleHitTest=_hitManager.onHit(char,
											_vecTiles[newGrid.left * _rwCount + newGrid.top],
											6);
						hasHitLeft ||= angleHitTest;
						hasHitTop ||= angleHitTest;
					}else{
						if (!hasHitTop) {
							hasHitLeft||=_hitManager.onHit(char,
												_vecTiles[newGrid.left * _rwCount + newGrid.top],
												4);
						}
						if (!hasHitLeft) {
							hasHitTop||=_hitManager.onHit(char,
												_vecTiles[newGrid.left * _rwCount + newGrid.top],
												2);
						}
					}
				}else if (hitRight&&hitTop){
					//右上
					hasHitRight = false;
					for (rw = newGrid.top+1; rw <= newGrid.bottom; rw++ ) {
						hasHitRight ||= _hitManager.onHit(char,
										                _vecTiles[newGrid.right * _rwCount + rw],
										                8);
					}
					
					hasHitTop = false;
					for (cl = newGrid.left; cl <= newGrid.right-1; cl++ ) {
						hasHitTop ||= _hitManager.onHit(char,
										                _vecTiles[cl * _rwCount + newGrid.top],
										                4);
					}
					
					if ((!hasHitTop) && (!hasHitRight)) {
						angleHitTest=_hitManager.onHit(char,
											_vecTiles[newGrid.right * _rwCount + newGrid.top],
											12);
						hasHitRight ||= angleHitTest;
						hasHitTop ||= angleHitTest;
					}else{
						if (!hasHitTop) {
							hasHitRight||=_hitManager.onHit(char,
												_vecTiles[newGrid.right * _rwCount + newGrid.top],
												8);
						}
						if (!hasHitRight) {
							hasHitTop||=_hitManager.onHit(char,
												_vecTiles[newGrid.right * _rwCount + newGrid.top],
												4);
						}
					}
				}else if (hitRight&&hitBottom){
					//右下
					hasHitRight = false;
					for (rw = newGrid.top; rw <= newGrid.bottom-1; rw++ ) {
						hasHitRight ||= _hitManager.onHit(char,
										                _vecTiles[newGrid.right * _rwCount + rw],
										                8);
					}
					
					hasHitBottom = false;
					for (cl = newGrid.left; cl <= newGrid.right-1; cl++ ) {
						hasHitBottom ||= _hitManager.onHit(char,
										                _vecTiles[cl * _rwCount + newGrid.bottom],
										                1);
					}
					
					if ((!hasHitBottom) && (!hasHitRight)) {
						angleHitTest=_hitManager.onHit(char,
											_vecTiles[newGrid.right * _rwCount + newGrid.bottom],
											9);
						if (char.v.x>char.v.y) {
							hasHitRight ||= angleHitTest;
						}else{
							hasHitBottom ||= angleHitTest;
						}
					}else{
						if (!hasHitBottom) {
							hasHitRight ||= _hitManager.onHit(char,
												_vecTiles[newGrid.right * _rwCount + newGrid.bottom],
												8);
						}
						if (!hasHitRight) {
							hasHitBottom ||= _hitManager.onHit(char,
												_vecTiles[newGrid.right * _rwCount + newGrid.bottom],
												1);
						}
					}
				}else if (hitLeft&&hitBottom){
					//左下
					hasHitLeft = false;
					for (rw = newGrid.top; rw <= newGrid.bottom-1; rw++ ) {
						hasHitLeft ||= _hitManager.onHit(char,
										                _vecTiles[newGrid.left * _rwCount + rw],
										                2);
					}
					
					hasHitBottom = false;
					for (cl = newGrid.left+1; cl <= newGrid.right; cl++ ) {
						hasHitBottom ||= _hitManager.onHit(char,
										                _vecTiles[cl * _rwCount + newGrid.bottom],
										                1);
					}
					
					if ((!hasHitBottom) && (!hasHitLeft)) {
						angleHitTest=_hitManager.onHit(char,
											_vecTiles[newGrid.left * _rwCount + newGrid.bottom],
											3);
						hasHitBottom ||= angleHitTest;
						hasHitLeft ||= angleHitTest;
					}else{
						if (!hasHitBottom) {
							hasHitLeft||=_hitManager.onHit(char,
												_vecTiles[newGrid.left * _rwCount + newGrid.bottom],
												2);
						}
						if (!hasHitLeft) {
							hasHitBottom||=_hitManager.onHit(char,
												_vecTiles[newGrid.left * _rwCount + newGrid.bottom],
												1);
						}
					}
				}else if (hitTop){
					//上
					hasHitTop = false;
					for (cl = newGrid.left; cl <= newGrid.right; cl++ ) {
						hasHitTop ||= _hitManager.onHit(char,
										                _vecTiles[cl * _rwCount + newGrid.top],
										                4);
					}
				}else if (hitRight){
					//右
					hasHitRight = false;
					for (rw = newGrid.top; rw <= newGrid.bottom; rw++ ) {
						hasHitRight ||= _hitManager.onHit(char,
										                _vecTiles[newGrid.right * _rwCount + rw],
										                8);
					}
				}else if (hitBottom){
					//下
					hasHitBottom = false;
					for (cl = newGrid.left; cl <= newGrid.right; cl++ ) {
						hasHitBottom ||= _hitManager.onHit(char,
										                _vecTiles[cl * _rwCount + newGrid.bottom],
										                1);
					}

				}else if (hitLeft){
					//左
					hasHitLeft = false;
					for (rw = newGrid.top; rw <= newGrid.bottom; rw++ ) {
						hasHitLeft ||= _hitManager.onHit(char,
										                _vecTiles[newGrid.left * _rwCount + rw],
										                2);
					}
				}
				
				//
				if (hasHitTop) {
					char.y = _tileLayer.y + oldGrid.top * _tileHeight-char.correctY+1;
					//char.v.y = char.a.y = 0;
					char.hitFlag |= 1;
				}else {
					char.hitFlag &= (~1);
				}
				
				if (hasHitBottom) {
					char.y = _tileLayer.y + newGrid.bottom* _tileHeight-oldBound.height-char.correctY;
					//char.v.y = char.a.y = 0;
					char.hitFlag |= 4;
				}else{
					char.hitFlag &= (~4);
				}
				
				if (hasHitLeft) {
					char.x = _tileLayer.x + oldGrid.left * _tileWidth-char.correctX+1;
					//char.v.x = char.v.y = 0;
					char.hitFlag |= 8;
				}else{
					char.hitFlag &= (~8);
				}
				
				if (hasHitRight) {
					char.x = _tileLayer.x + newGrid.right* _tileWidth-oldBound.width-char.correctX-1;
					//char.v.x = char.v.y = 0;
					char.hitFlag |= 2;
				}else{
					char.hitFlag &= (~2);
				}
				
				if (char == _mainChar) {
					var dx:Number = char.x - oldx;
					var dy:Number = char.y - oldy;
					
					var dCl:Number = dx / _tileWidth;
					var dRw:Number = dy / _tileHeight;
					
					var oldViewPortCl:Number = _mapData.viewPortCl;
					var oldViewPortRw:Number = _mapData.viewPortRw;
					
					_mapData.viewPortCl += dCl;
					_mapData.viewPortRw += dRw;
					
					//if (_mapData.viewPortCl == oldViewPortCl) {
						//char.x = oldx;
					//}else {
						dCl = _mapData.viewPortCl - oldViewPortCl;
						dx -= dCl * _tileWidth;
						char.x = oldx + dx;
					//}
					//
					//if (_mapData.viewPortRw == oldViewPortRw) {
						//char.y = oldy;
					//}else {
						dRw = _mapData.viewPortRw - oldViewPortRw;
						dy -= dRw * _tileHeight;
						char.y = oldy + dy;
					//}
				}
				
				addGlobalForce(char);
			}
		}
		private function addGlobalForce(char:Character):void {
			char.v.x += _globalForce.x;
			char.v.y += _globalForce.y;
		}
		
		
		//--
		private function render():void {
			//_lastViewport = _mapData.viewPort.clone();
			var tile:AbstractTile;
			
			for (var cl:int = 0; cl < _clCount; cl++) {
				for (var rw:int = 0; rw < _rwCount; rw++) {
					tile = _vecTiles[cl * _rwCount + rw];
					tile.showTile(_mapData.getScreenData(cl, rw));
				}
			}
			_tileLayer.x = -getDecimal(_mapData.viewPort.x)*tile.getTileWidth();
			_tileLayer.y = -getDecimal(_mapData.viewPort.y) * tile.getTileHeight();
		}		
		
		private function getDecimal(num:Number):Number {
			return num-Math.floor(num);
		}
		//} endregion
		
		//{ region 存取器
		public function get mapData():MapData {
			return _mapData;
		}
		
		public function set mapData(value:MapData):void {
			_mapData = value;
		}				
		
		public function get hitManager():IHitManager {
			return _hitManager;
		}
		
		public function set hitManager(value:IHitManager):void {
			_hitManager = value;
		}
		
		public function get globalForce():Point {
			return _globalForce;
		}
		
		public function get mainChar():Character {
			return _mainChar;
		}
		
		public function set mainChar(value:Character):void {
			_mainChar = value;
			_chars.unshift(_mainChar);
		}
		
		public function addChar(char:Character):Vector.<Character> {
			if (_chars.indexOf(char) == -1) {
				_chars.push(char);
			}
			return _chars;
		}

		//} endregion

	}

}